#include "stm32f1xx_ll_usart.h"

#ifndef qc_obj
#include "bsp.h"
#include "pincfg.h"
#include "os_obj.h"
#include "mbapp.h"
#include "com_def.h"

#define qc_rx_enable()
#define qc_tx_enable()
qc_obj_type qc_obj;
#define qc_port USART3
#define qc_uart_irqn USART3_IRQn
static void qc_cb_set(void)
{
}
static void qc_port_hal_cfg(void) {}
#endif

static void qc_cb_set(void);
static void qc_tx1_rx0_enable(uint8_t mode);
static void qc_port_Init(uu8 mbMode, uint32_t ulBaudRate, mb_parity_type eParity);
static void qc_port_send(void);
static void qc_port_hal_cfg(void);
static void (*qc_byte_send)(uint8_t dat);

/*****************************************************************************
 * @brief UART OPT
 *****************************************************************************/
// 数据收发
#define UART_SEND_DAT(dat) qc_port->DR = dat
#define UART_RCV_DAT() qc_port->DR

// 缓冲状态
#define UART_RX_NE_ST() ((qc_port->SR & USART_SR_RXNE) != 0) // rx not empty
#define UART_TX_NF_ST() (0 != (qc_port->SR & USART_SR_TXE))	 // tx not full
#define UART_TX_TC_ST() (qc_port->SR & (USART_SR_TC))
#define UART_TX_TC_CLR()

// 接收控制
#define UART_RX_EN() qc_port->CR1 |= (USART_CR1_UE | USART_CR1_RE)
#define UART_RX_INT_EN() qc_port->CR1 |= USART_CR1_RXNEIE
#define UART_RX_INT_DIS() qc_port->CR1 &= ~(USART_CR1_RXNEIE | USART_CR1_RE)

// 发送控制
#define UART_TX_EN() qc_port->CR1 |= (USART_CR1_UE | USART_CR1_TE)

#define UART_TX_TDE_EN() cset_mask(qc_port->CR1, USART_CR1_TCIE, USART_CR1_TXEIE)
#define UART_TX_TC_EN() cset_mask(qc_port->CR1, USART_CR1_TXEIE, USART_CR1_TCIE)
#define UART_TX_INT_DIS() clr_mask(qc_port->CR1, USART_CR1_TCIE | USART_CR1_TXEIE)

// 错误标志及清除
#define UART_RX_ERR_FLAG (USART_SR_PE | USART_SR_ORE)
#define UART_RX_ERR_CLR()

/*****************************************************************************
 * @brief mb_byte_send
 * @param   dat
 * @return  none
 * @ Pass/ Fail criteria: none
 *****************************************************************************/

static void qc_rtu_byte_send(uint8_t dat)
{
	UART_SEND_DAT(dat);
}

/*****************************************************************************
 * @brief UART interrupt routine.
 * @param   none
 * @return  none
 *****************************************************************************/
void qc_isr()
{
	volatile uint32_t IntSt;
	volatile uint8_t Data;

	IntSt = qc_port->SR;

	if (IntSt & (USART_SR_RXNE | USART_SR_ORE))
	{
		Data = UART_RCV_DAT();

		if ((IntSt & UART_RX_ERR_FLAG) != 0)
		{
			if (qc_obj.rx_cnt >= 1)
			{
				qc_obj.err_hal = 1;
			}
			UART_RX_ERR_CLR();
		}

		qc_data_rcv(&qc_obj, Data);
	}
	else if ((qc_obj.tx_size <= qc_obj.tx_cnt) && (IntSt & USART_SR_TC))
	{
		qc_send_end(&qc_obj);
		qc_tx1_rx0_enable(0);
		UART_TX_TC_CLR();
	}
	else if (IntSt & USART_SR_TXE)
	{
		if (qc_data_send(&qc_obj, qc_rtu_byte_send, 1))
		{
			UART_TX_TC_EN();
		}
	}
	else
	{
	}
}

/*****************************************************************************
 * @brief   	com modle init .
 * @param   none
 * @return  none
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
static void qc_port_Init(uu8 qcMode, uint32_t ulBaudRate, mb_parity_type eParity)
{
	LL_USART_InitTypeDef cfg;

	qc_port_hal_cfg();

	qc_cb_set();
	qc_obj.mode = qcMode;
	qc_obj.dat_send = qc_port_send;

	qc_byte_send = qc_rtu_byte_send;

	cfg.BaudRate = ulBaudRate;
	cfg.TransferDirection = LL_USART_DIRECTION_TX_RX;
	cfg.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
	cfg.OverSampling = LL_USART_OVERSAMPLING_16;

	// rtu mode
	if (MB_PAR_NONE == eParity)
	{
		cfg.Parity = LL_USART_PARITY_NONE;
		cfg.StopBits = LL_USART_STOPBITS_2;
		cfg.DataWidth = LL_USART_DATAWIDTH_8B;
	}
	else if (MB_PAR_NONE_1S == eParity)
	{
		cfg.Parity = LL_USART_PARITY_NONE;
		cfg.StopBits = LL_USART_STOPBITS_1;
		cfg.DataWidth = LL_USART_DATAWIDTH_8B;
	}
	else if (MB_PAR_ODD == eParity)
	{
		cfg.Parity = LL_USART_PARITY_ODD;
		cfg.StopBits = LL_USART_STOPBITS_1;
		cfg.DataWidth = LL_USART_DATAWIDTH_9B;
	}
	else
	{
		cfg.Parity = LL_USART_PARITY_EVEN;
		cfg.StopBits = LL_USART_STOPBITS_1;
		cfg.DataWidth = LL_USART_DATAWIDTH_9B;
	}

	// rtu timer
	if (ulBaudRate > 19200)
	{
		qc_obj.tim_sv = 3;
	}
	else
	{
		qc_obj.tim_sv = (com_timer_cal(ulBaudRate, (35 * 11 + 9) / 10, 300, 12000) + 99) / 100;
	}

	LL_USART_Init(qc_port, &cfg);
	LL_USART_Enable(qc_port);

	nvic_irq_set(qc_uart_irqn, 0x06, 1);

	qc_tx1_rx0_enable(0);

	UART_TX_EN();
}

/*****************************************************************************
 *
 * @brief   Uart En or Dis.
 *
 * @param   none
 *
 * @return  none
 *
 * @ Pass/ Fail criteria: none
 *****************************************************************************/

static void qc_tx1_rx0_enable(uint8_t mode)
{
	volatile uint8_t u8Temp;

	if (0 == mode)
	{
		qc_rx_enable();

		UART_TX_INT_DIS();
		UART_RX_EN();

		u8Temp = qc_port->DR;
		while ((qc_port->SR & (USART_SR_RXNE | USART_SR_ORE)) != 0)
		{
			u8Temp = qc_port->DR;
			__DSB();
		}

		UART_RX_INT_EN();
	}
	else
	{
		qc_tx_enable();

		UART_RX_INT_DIS();

		UART_TX_TDE_EN();
	}
}

/*****************************************************************************
 *
 * @brief   Send data.
 *
 * @param   none
 *
 * @return  none
 *
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
static void qc_port_send(void)
{
	qc_tx1_rx0_enable(1);
}

/*****************************************************************************
 * @brief   sim_mbport_keep
 * @param   none
 * @return  none
 *****************************************************************************/
#ifndef qc_obj
void qc_sim_mbport_keep(void)
{
	qc_port_Init(0, 9600, MB_PAR_NONE);
}
#endif